package com.ict.web.controller.yzq;

import com.ict.common.constant.Constants;
import com.ict.common.core.domain.AjaxResult;
import com.ict.common.core.domain.entity.SysUser;
import com.ict.common.core.domain.model.LoginUser;
import com.ict.common.utils.StringUtils;
import com.ict.common.utils.XmlUtils;
import com.ict.framework.web.service.SysLoginService;
import com.ict.framework.web.service.SysPermissionService;
import com.ict.framework.web.service.TokenService;
import com.ict.system.service.ISysRoleService;
import com.ict.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.cert.X509Certificate;
import java.util.Set;

@RequestMapping("/login")
@RestController
@Slf4j
public class LoginController {
    @Value("${cas.server-url-prefix}")
    private String prefixUrl;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private SysLoginService loginService;
    @Autowired
    private ISysRoleService roleService;
    @Autowired
    private SysPermissionService permissionService;
    @GetMapping("/login")
    public AjaxResult validateLogin(@RequestParam(name = "ticket") String ticket,
                                @RequestParam(name = "service") String service) {
        log.info("Rest api login.");
        try {
            String validateUrl = prefixUrl + "/p3/serviceValidate";
            // 调用 CAS Server 接口验证 ST 是否有效
            String res = getSTValidate(validateUrl, ticket, service);
            log.info("res." + res);
            final String error = XmlUtils.getTextForElement(res, "authenticationFailure");
            if (StringUtils.isNotEmpty(error)) {
                throw new Exception(error);
            }
            // 获取返回的数据中的用户名称
            final String principal = XmlUtils.getTextForElement(res, "user");
            if (StringUtils.isEmpty(principal)) {
                throw new Exception("No principal was found in the response from the CAS server.");
            }
            log.info("-------token----username---" + principal);
            //todo. 根据返回的 username 校验用户是否有效，然后走常规的登录完成的逻辑，生成应用内部 token
            SysUser sysUser = userService.selectUserByUserName(principal);
            //未分配的角色初始化用户角色权限
            if(sysUser.getRoles().size()==0){
                sysUser.setDeptId(112L);
                userService.updateUser(sysUser);
                Set<String> roles = permissionService.getRolePermission(sysUser);
                if(roles.size()==0){
                    roleService.insertAuthUsers(110L,new Long[]{sysUser.getUserId()});
                }
            }
            AjaxResult ajax = AjaxResult.success();
            sysUser.setPassword("test123");
            // 生成令牌
            String token = loginService.login(sysUser.getUserName(), sysUser.getPassword(), null, null);
            ajax.put(Constants.TOKEN, token);
            ajax.put("res",res);
            return ajax;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.error("登陆失败!");
    }

    /**
     * 验证 ST
     */
    public static String getSTValidate(String url, String st, String service) {
        try {
            url = url + "?service=" + service + "&ticket=" + st;
            CloseableHttpClient httpclient = createHttpClientWithNoSsl();
            HttpGet httpget = new HttpGet(url);
            HttpResponse response = httpclient.execute(httpget);
            String res = readResponse(response);
            return res == null ? null : (res == "" ? null : res);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 创建模拟客户端（针对 https 客户端禁用 SSL 验证）
     *
     * @return
     * @throws Exception
     */
    private static CloseableHttpClient createHttpClientWithNoSsl() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    @Override
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                        // don't check
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                        // don't check
                    }
                }};
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(null, trustAllCerts, null);
        LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(ctx);
        return HttpClients.custom()
                .setSSLSocketFactory(sslSocketFactory)
                .build();
    }

    /**
     * 读取 response body 内容为字符串
     *
     * @param response
     * @return
     * @throws IOException
     */
    private static String readResponse(HttpResponse response) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        String result = new String();
        String line;
        while ((line = in.readLine()) != null) {
            result += line;
        }
        return result;
    }
}
